package com.choosefine.paycenter.common.utils;

import com.google.common.base.Joiner;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.web.util.UriComponentsBuilder;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Comments：Uri操作工具类
 * Author：Jay Chang
 * Create Date：2017/4/14
 * Modified By：
 * Modified Date：
 * Why & What is modified：
 * Version：v1.0
 */
public class UriUtils {
    private static UriUtils uriUtils;

    private UriUtils(){}

    public static synchronized UriUtils getInstance(){
        return null != uriUtils ? uriUtils : (uriUtils = new UriUtils());
    }

    /**
     * 如果map的类型是LinkedHashMap则生成的uri的key顺序会按照put进params的顺序排列
     * @param params 键值对
     * @return
     */
    public String paramMap2Uri(final Map<String,Object> params ){
        return Joiner.on("&").withKeyValueSeparator("=").join(params);
    }

    /**
     *
     * @param params 键值对
     * @param keySeqList  key数组(生成的uri的key的顺序按此数组中的key的顺序排列)
     * @return
     */
    public String paramMap2Uri(final Map<String,Object> params ,final List<String> keySeqList){
        final String [] keySeqArr = keySeqList.toArray(new String[0]);
        return paramMap2Uri(params,keySeqArr);
    }

    /**
     *
     * @param params  键值对
     * @param keySeqArr key数组(生成的uri的key的顺序按此数组中的key的顺序排列)
     * @return
     */
    public String paramMap2Uri(final Map<String,Object> params ,final String ... keySeqArr){
        int sizeParams  = 0 ,sizeKeySeqArr = 0;
        if(null == params || (sizeParams = params.size()) == 0){
            throw new IllegalArgumentException("params can not be null or empty");
        }
        if(null == keySeqArr || (sizeKeySeqArr = keySeqArr.length) == 0){
            throw new IllegalArgumentException("keySeqArr can not be null or empty");
        }
        if(sizeKeySeqArr > sizeParams){
            throw new IllegalArgumentException("params size must greater thant keySeqArr size");
        }
        Map<String,Object> tmpParams = new LinkedHashMap<>();
        for(String key : keySeqArr){
            tmpParams.put(key,params.get(key));
        }
        return Joiner.on("&").withKeyValueSeparator("=").join(tmpParams);
    }

    /**
     * @param object
     * @param uriStr 格式key1={value1}&key2={value2}
     * @return
     */
    public String object2Uri(final Object object ,final String uriStr)  {
        try {
            Map<String,String> params = BeanUtils.describe(object);
            return UriComponentsBuilder.fromUriString(uriStr).buildAndExpand(params).toUriString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     *
     * @param object
     * @param keySeqArr
     * @return
     */
    public String object2Uri(final Object object ,final String ... keySeqArr)  {
        Class clazz = object.getClass();
        Field[] fields = clazz.getDeclaredFields();
        Map<String,Object> params = new HashMap<>();
        if(null != fields && fields.length > 0) {
            for (Field field : fields) {
                String fieldName = field.getName();
                Method getMethod = null;
                try {
                    getMethod = clazz.getMethod("get"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1),new Class[]{});
                    Object value = getMethod.invoke(object,new Object[]{});
                    params.put(fieldName,value);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
            return paramMap2Uri(params,keySeqArr);
        }
        throw new IllegalArgumentException("object has no field");
    }

    public String encode(String str,String encode){
        String result = null;
        try {
            result = URLEncoder.encode(str,encode);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    public String decode(String str,String encode){
        String result = null;
        try {
            result = URLDecoder.decode(str,encode);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }
}
